﻿using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GongSolutions.Wpf.DragDrop;
using HelloWPF.Study.WPFControls.Command;
using HelloWPF.Study.WPFControls.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace HelloWPF.Study.WPFControls.ViewModel
{
    public class TreeViewDynamicViewModel : ViewModelBase, IDragSource, IDropTarget
    {
        private ObservableCollection<ContextMenuVM> _menuContextCommandList;
        public ObservableCollection<ContextMenuVM> MenuContextCommandList
        { 
            get
            {
                return _menuContextCommandList;
            }
            set
            {
                _menuContextCommandList = value;
                RaisePropertyChanged();
            }
        }
      
        /// <summary>
        /// 选中的Menu
        /// </summary>
        public MenuItemBase _selectedMenu;
        public MenuItemBase SelectedMenu
        {
            get { return _selectedMenu; }
            set
            {
                _selectedMenu = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        /// Menu控件的数据源属性
        /// </summary>
        public ObservableCollection<MenuItemBase> _menuList;
        public ObservableCollection<MenuItemBase> MenuList
        {
            get { return _menuList; }
            set
            {
                _menuList = value;
                RaisePropertyChanged();
            }
        }

        #region 命令属性
        /// <summary>
        /// 选中节点命令
        /// </summary>
        public RelayCommand<MenuItemBase> SelectedItemChangedCommand { get; set; }

        /// <summary>
        /// 拖拽节点落下命令
        /// </summary>
        public RelayCommand<MenuItemBase> DragDropCommand { get; set; }

        public ICommand MICommand
        {
            get
            {
                return new CommandBase()
                {
                    DoExecute = o =>
                    {
                        MessageBox.Show(o.ToString());
                    },
                    DoCanExecute = o => { return true; }
                };
            }
        }
        #endregion

        /// <summary>
        /// Ctor
        /// </summary>
        public TreeViewDynamicViewModel()
        {
            MenuList = new ObservableCollection<MenuItemBase>();
            #region 递归方式添加节点
            {
                List<MenuItemBase> allMenuList = GetMenuList();//基础数据菜单数据-没有组织结构的源数据
                BuildTree(allMenuList, MenuList, null, 0);
            }
            #endregion
            SelectedItemChangedCommand = new RelayCommand<MenuItemBase>((obj) =>
            {
               
            });
            //事件命令
            DragDropCommand = new RelayCommand<MenuItemBase>((obj) =>
            {
                MessageBox.Show("123456");
            });
        }

        /// <summary>
        /// 获取菜单数据
        /// </summary>
        /// <returns></returns>
        private List<MenuItemBase> GetMenuList()
        {
            List<MenuItemBase> list = new List<MenuItemBase>();
            //添加6个根节点
            int rootMenuLoop = 6;
            for (int i = 0; i < rootMenuLoop; i++)
            {
                int number = i + 1;
                GeneralMenu rootMenu = new GeneralMenu();
                rootMenu.Id = number;//1,2,3,4,5,6
                rootMenu.Name = $"MenuName_{number}";
                rootMenu.ParentId = 0;//0:表示没有父节点，是根节点
                rootMenu.LevelRelationship = "1";
                list.Add(rootMenu);
            }

            //1.第1个根节点菜单项的子菜单
            for (int i = 0; i < 2; i++)
            {
                int number = rootMenuLoop + 1 + i;
                GeneralMenu childMenu = new GeneralMenu();
                childMenu.Id = number;//7,8
                childMenu.Name = $"MenuName_{number}";
                childMenu.ParentId = 1;//1:是第1个根节点菜单项的子菜单
                childMenu.LevelRelationship = $"1,{number}";
                list.Add(childMenu);
            }

            //2.第2个根节点菜单项的子菜单
            for (int i = 0; i < 3; i++)
            {
                int number = (rootMenuLoop + 2) + 1 + i;
                GeneralMenu childMenu = new GeneralMenu();
                childMenu.Id = number;//9,10,11
                childMenu.Name = $"MenuName_{number}";
                childMenu.ParentId = 2;//2:是第2个根节点菜单项的子菜单
                childMenu.LevelRelationship = $"2,{number}";
                list.Add(childMenu);
            }

            {
                GeneralMenu childMenu = new GeneralMenu();
                childMenu.Id = 12;//12
                childMenu.Name = $"MenuName_{12}";
                childMenu.ParentId = 9;//9
                childMenu.LevelRelationship = $"2,9,{childMenu.Id}";
                list.Add(childMenu);
            }

            {
                GeneralMenu childMenu = new GeneralMenu();
                childMenu.Id = 13;//13
                childMenu.Name = $"MenuName_{13}";
                childMenu.ParentId = 12;//12
                childMenu.LevelRelationship = $"2,9,12,{childMenu.Id}";
                list.Add(childMenu);
            }
            return list;
        }

        /// <summary>
        /// 递归加载菜单项数据(构建树形结构)
        /// </summary>
        /// <param name="allMenus"></param>
        /// <param name="menusList"></param>
        /// <param name="pMenu"></param>
        /// <param name="parentId"></param>
        private void BuildTree(List<MenuItemBase> allMenus, ObservableCollection<MenuItemBase> menusList, MenuItemBase parentMenu, int parentId)
        {
            var subMenuList = allMenus.Where(m => m.ParentId == parentId);//查询子菜单
            //遍历子菜单
            foreach (var subMenu in subMenuList)
            {
                GeneralMenu menuItem = new GeneralMenu();
                menuItem.Id = subMenu.Id;
                menuItem.Name = subMenu.Name;
                menuItem.ParentId = subMenu.ParentId;
                if (parentMenu != null)
                {
                    parentMenu.SubMenuItems.Add(menuItem);
                }
                else
                {
                    menusList.Add(menuItem);
                }
                //递归
                BuildTree(allMenus, menusList, menuItem, subMenu.Id);
            }
        }

        #region DragDrop members

        #region IDragSource members
        /// <summary>
        /// 查询是否可以开始拖动(依赖于CanStartDrag的返回结果)
        /// 拖动时触发
        /// </summary>
        /// <param name="dragInfo"></param>
        public void StartDrag(IDragInfo dragInfo)
        {
            dragInfo.Data = dragInfo.SourceItem;
            dragInfo.Effects = dragInfo.Data != null ? DragDropEffects.Move | DragDropEffects.Copy : DragDropEffects.None;
        }

        /// <summary>
        /// 可以检查是否允许拖放操作
        /// 选中节点就触发
        /// </summary>
        /// <param name="dragInfo"></param>
        /// <returns></returns>
        public bool CanStartDrag(IDragInfo dragInfo)
        {
            SelectedMenu = dragInfo.SourceItem as MenuItemBase;
            UpdateMenuContext();
            //根节点不能拖拽
            if (SelectedMenu != null && SelectedMenu.ParentId != 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 发生落下
        /// </summary>
        /// <param name="dropInfo"></param>
        public void Dropped(IDropInfo dropInfo)
        {
            var targetItem = dropInfo.TargetItem as MenuItemBase;
            var sourceItem = dropInfo.DragInfo.SourceItem as MenuItemBase;

            //Has target and has source
            if (targetItem != null && sourceItem != null)
            {
                if (MessageBox.Show("Would you like to drop " + sourceItem.Name + " into " + targetItem.Name + "", "", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                {
                    try
                    {
                        //1.给新目标添加新元素
                        ToTargetItemAddItem(sourceItem, targetItem, MenuList);

                        //2.从被拖拽项的父元素中移除掉该被拖拽项
                        RemoveSourceItem(sourceItem, targetItem, MenuList);

                        //3.改变源Item的父Id
                        sourceItem.ParentId = targetItem.Id;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
            }
            //MessageBox.Show("发生落下");
        }

        /// <summary>
        /// 拖拽和落下操作完成
        /// </summary>
        /// <param name="operationResult"></param>
        /// <param name="dragInfo"></param>
        public void DragDropOperationFinished(DragDropEffects operationResult, IDragInfo dragInfo)
        {
            //MessageBox.Show("拖拽和落下操作完成");
        }

        /// <summary>
        /// 拖拽到非法区域触发
        /// </summary>
        public void DragCancelled()
        {
            MessageBox.Show("不能拖拽");
        }

        public bool TryCatchOccurredException(Exception exception)
        {
            return false;
        }
        #endregion

        #region IDropTarget members
        /// <summary>
        /// 如果没有指定dropInfo.Effects = DragDropEffects.Move;
        /// 那么就会触发DragCancelled()
        /// </summary>
        /// <param name="dropInfo"></param>
        public void DragOver(IDropInfo dropInfo)
        {
            dropInfo.Effects = DragDropEffects.Move;
        }

        /// <summary>
        /// 拖拽鼠标左键松手时触发
        /// </summary>
        /// <param name="dropInfo"></param>
        public void Drop(IDropInfo dropInfo)
        {
            //MessageBox.Show("拖拽鼠标左键松手时触发");
        }
        #endregion

        #endregion
     
        /// <summary>
        /// 给新目标添加新元素
        /// </summary>
        /// <param name="sourceItem"></param>
        /// <param name="targetItem"></param>
        private void ToTargetItemAddItem(MenuItemBase sourceItem, MenuItemBase targetItem, ObservableCollection<MenuItemBase> menuList)
        {
            if (menuList.Count == 0)
            {
                return;
            }
            foreach (var menu in menuList)
            {
                if (menu.Id == targetItem.Id)
                {
                    menu.SubMenuItems.Add(sourceItem);
                    return;
                }
                else
                {
                    ToTargetItemAddItem(sourceItem, targetItem, menu.SubMenuItems);
                }
            }
        }

        /// <summary>
        /// 从被拖拽项的父元素中移除掉该被拖拽项
        /// </summary>
        /// <param name="sourceItem"></param>
        /// <param name="targetItem"></param>
        private void RemoveSourceItem(MenuItemBase sourceItem, MenuItemBase targetItem, ObservableCollection<MenuItemBase> menuList)
        {
            if (sourceItem.ParentId == 0)//根节点
            {
                var rootMenu = menuList.FirstOrDefault(menu => menu.Id == sourceItem.Id);
                menuList.Remove(rootMenu);
                return;
            }

            if (menuList.Count == 0)
            {
                return;
            }
            foreach (var menu in menuList)
            {
                if (menu.Id == sourceItem.ParentId)
                {
                    menu.SubMenuItems.Remove(sourceItem);
                    return;
                }
                else
                {
                    RemoveSourceItem(sourceItem, targetItem, menu.SubMenuItems);
                }
            }
        }

        private TreeViewItem GetNearestContainer(UIElement element)
        {
            // Walk up the element tree to the nearest tree view item.
            TreeViewItem container = element as TreeViewItem;
            while ((container == null) && (element != null))
            {
                element = VisualTreeHelper.GetParent(element) as UIElement;
                container = element as TreeViewItem;
            }
            return container;
        }

        /// <summary>
        /// 更新菜单
        /// </summary>
        private void UpdateMenuContext()
        {
            MenuContextCommandList = new ObservableCollection<ContextMenuVM>();
            ContextMenuVM contextNewMenu = new ContextMenuVM();
            contextNewMenu.MenuDisplayname = "Add New Item";
            contextNewMenu.MenuCommandParam = "current";

            ContextMenuVM contextExistMenu = new ContextMenuVM();
            contextExistMenu.MenuDisplayname = "Add Exist Item";
            contextExistMenu.MenuCommandParam = "current";

            if (SelectedMenu.ParentId == 0 || SelectedMenu.Type == Utility.ItemType.Folder)
            {
                contextNewMenu.SubContextMenu = new ObservableCollection<ContextMenuVM>()
                {
                    new ContextMenuVM() { MenuDisplayname = "New Folder", MenuCommand = AddNewFolder, MenuCommandParam = "InsertBefore" },
                    new ContextMenuVM() { MenuDisplayname = "New File", MenuCommand = AddNewFile, MenuCommandParam = "InsertAfter" },
                };
                contextExistMenu.SubContextMenu = new ObservableCollection<ContextMenuVM>()
                {
                    new ContextMenuVM() { MenuDisplayname = "Exist Folder", MenuCommand = AddExistFolder, MenuCommandParam = "InsertBefore" },
                    new ContextMenuVM() { MenuDisplayname = "Exist File", MenuCommand = AddExistFile, MenuCommandParam = "InsertAfter" },
                };
            }
            else
            {
                contextNewMenu.SubContextMenu = new ObservableCollection<ContextMenuVM>()
                {
                    new ContextMenuVM() { MenuDisplayname = "New File", MenuCommand = AddNewFile, MenuCommandParam = "InsertAfter" },
                };
                contextExistMenu.SubContextMenu = new ObservableCollection<ContextMenuVM>()
                {
                    new ContextMenuVM() { MenuDisplayname = "Exist File", MenuCommand = AddExistFile, MenuCommandParam = "InsertAfter" },
                };
            }
            MenuContextCommandList.Add(contextNewMenu);
            MenuContextCommandList.Add(contextExistMenu);
        }

        #region 添加文件/文件夹
        private RelayCommand<object> _addNewFolder;
        public RelayCommand<object> AddNewFolder
        {
            get
            {
                if (_addNewFolder == null)
                {
                    _addNewFolder = new RelayCommand<object>(new Action<object>(o =>
                    {
                        string a = o.ToString();

                    }));
                }
                return _addNewFolder;
            }
        }

        private RelayCommand<object> _addNewFile;
        public RelayCommand<object> AddNewFile
        {
            get
            {
                if (_addNewFile == null)
                {
                    _addNewFile = new RelayCommand<object>(new Action<object>(o =>
                    {
                        string a = o.ToString();

                    }));
                }
                return _addNewFile;
            }
        }
        private RelayCommand<object> _addExistFolder;
        public RelayCommand<object> AddExistFolder
        {
            get
            {
                if (_addExistFolder == null)
                {
                    _addExistFolder = new RelayCommand<object>(new Action<object>(o =>
                    {
                        string a = o.ToString();

                    }));
                }
                return _addExistFolder;
            }
        }

        private RelayCommand<object> _addExistFile;
        public RelayCommand<object> AddExistFile
        {
            get
            {
                if (_addExistFile == null)
                {
                    _addExistFile = new RelayCommand<object>(new Action<object>(o =>
                    {
                        string a = o.ToString();

                    }));
                }
                return _addExistFile;
            }
        }
        #endregion
    }
}


